#ifndef MY_DB_HPP
#define MY_DB_HPP

#include "util.hpp"
#include <mutex>
#include <assert.h>

//数据管理模块
class user_table
{
private:
    //MySQL句柄
    MYSQL* _mysql;
    //互斥锁
    std::mutex _mutex;
public:

    user_table(const std::string& host,const std::string& user, 
        const std::string& passwd, 
        const std::string& dbname, unsigned int port = 3306)
    {
        _mysql = mysql_util::mysql_create(host, user, passwd, dbname, port);
        assert(_mysql != NULL);
    }

    ~user_table()
    {
        mysql_util::mysql_destory(_mysql);
        _mysql = NULL;
    }

    //新增用户
    bool insert(Json::Value& user)
    {
#define INSERI_USER "insert into user values(null, '%s', SHA2('%s', 256), 1000, 0, 0);"

        std::string username = user["username"].asString();
        std::string password = user["password"].asString();

        //用户名字，密码都要有
        if(username.empty() || password.empty())
        {
            DLOG("input username or password");
            return false;
        }

        char sql[4096] = { 0 };
        sprintf(sql, INSERI_USER, username.c_str(), password.c_str());
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if(ret == false)
        {
            DLOG("insert user fail");
            return false;
        }
        return true;
    }

    //登录验证，并且返回完整信息
    //用户名 + 密码都要正确
    bool login(Json::Value& user)
    {
        std::string username = user["username"].asString();
        std::string password = user["password"].asString();

        //用户名字，密码都要有
        if(username.empty() || password.empty())
        {
            DLOG("input username or password");
            return false;
        }

#define LOGIN_USER "select id, score, total_count, win_count from user where username='%s' and password=SHA2('%s', 256);"

        char sql[4096] = { 0 };
        sprintf(sql, LOGIN_USER, username.c_str(), password.c_str());

        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if(ret == false)
            {
                DLOG("user login fail");
                return false;
            }

            //运行到这里说明已经正确登录了
            res = mysql_store_result(_mysql);
            //要么有一个数据，要么没有数据
            if(res == NULL)
            {
                DLOG("have no login user");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            DLOG("User information is not unique");
            return false;
        }
        MYSQL_ROW rows = mysql_fetch_row(res);

        user["id"] = (Json::UInt64)std::stol(rows[0]);
        user["score"] = (Json::UInt64)std::stol(rows[1]);
        user["total_count"] = std::stoi(rows[2]);
        user["win_count"] = std::stoi(rows[3]);

        mysql_free_result(res);
        return true;
    }

    //根据姓名找到用户信息
    bool select_by_name(const std::string& name, Json::Value& user)
    {
#define USER_BY_NAME "select id, score, total_count, win_count from user where username='%s';"

        char sql[4096] = { 0 };
        sprintf(sql, USER_BY_NAME, name.c_str());

        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if(ret == false)
            {
                DLOG("username not find");
                return false;
            }

            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                DLOG("have no  user info");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            DLOG("User information is not unique");
            return false;
        }
        MYSQL_ROW rows = mysql_fetch_row(res);

        user["id"] = (Json::UInt64)std::stol(rows[0]);
        user["name"] = name;
        user["score"] = (Json::UInt64)std::stol(rows[1]);
        user["total_count"] = std::stoi(rows[2]);
        user["win_count"] = std::stoi(rows[3]);

        mysql_free_result(res);
        return true;
    }

    //根据id找到用户信息
    bool select_by_id(const uint64_t id, Json::Value& user)
    {
#define USER_BY_ID "select username, score, total_count, win_count from user where id=%lu;"

        char sql[4096] = { 0 };
        sprintf(sql, USER_BY_ID, id);

        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if(ret == false)
            {
                DLOG("id not find");
                return false;
            }

            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                DLOG("have no  user info");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            DLOG("User information is not unique");
            return false;
        }
        MYSQL_ROW rows = mysql_fetch_row(res);

        user["id"] = (Json::UInt64)id;
        user["username"] = rows[0];
        user["score"] = (Json::UInt64)std::stol(rows[1]);
        user["total_count"] = std::stoi(rows[2]);
        user["win_count"] = std::stoi(rows[3]);

        mysql_free_result(res);
        return true;
    }

    //胜利增加30分数 总场次+1 胜利场次+1
    bool win(uint64_t id)
    {
#define USER_WIN "update user set score=score+30,total_count=total_count+1, win_count=win_count+1 where id=%lu;"

        char sql[4096] = { 0 };
        sprintf(sql, USER_WIN, id);

        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if(ret == false)
        {
            DLOG("win user info update fail");
            return false;
        }
        return true;
    }

    //失败减少30分数 总场次+1 别的不变
    bool lose(uint64_t id)
    {
#define USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%lu;"

        char sql[4096] = { 0 };
        sprintf(sql, USER_LOSE, id);

        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if(ret == false)
        {
            DLOG("lose user info update fail");
            return false;
        }
        return true;
    }

};


#endif